package at.fhooe.stefanirndorfer.sound;

import java.io.FileNotFoundException;
import java.nio.FloatBuffer;
import java.util.HashMap;

import org.lwjgl.openal.AL10;

import at.fhooe.stefanirndorfer.effects.EffectUtils;
import at.fhooe.stefanirndorfer.logging.Log;
import at.fhooe.stefanirndorfer.raycast.AcousticScanner;
import at.fhooe.stefanirndorfer.walls.GeometryManager;

/**
 * The SoundManager is supposed to exist only once in a project
 * it keeps all Sound objects
 * @author Stefan Irndorfer
 *
 */
public class SoundManager implements SoundEngineInterface{


	private final String PATH = "res/sound/";
	
	private HashMap<String, OpenALWave> soundMap;
	//private List<SoundPlayer> sources;
	private SoundListener listener;
	private OpenALSource sourcePool;
	private AcousticScanner acousticScanner;
	private GeometryManager geometryManager;

	
	
	public SoundManager() throws FileNotFoundException{
		OpenALUtil.createOpenAL();
		try {
			EffectUtils.setupEfx();
			EffectUtils.efxUtilTest();
			EffectUtils.silentTests();
		} catch (Exception e) {
			System.out.println("Error while setting up Effects");
			e.printStackTrace();
		}
		
		// allocate all available sources
	    OpenALSource.alGenSources();
		
		//sources = new ArrayList<SoundPlayer>();
		soundMap = new HashMap<String, OpenALWave>();
		
		sourcePool = new OpenALSource();
		listener = null;
		acousticScanner = null;
		geometryManager = new GeometryManager();
	}
	
	
	/**
	 * void setListenerValues()
	 *
	 *  We already defined certain values for the Listener, but we need
	 *  to tell OpenAL to use that data. This function does just that.
	 */
	void setListenerValues() {
	  AL10.alListener(AL10.AL_POSITION,    listener.getPosition());
	  AL10.alListener(AL10.AL_VELOCITY,    listener.getVelocity());
	  AL10.alListener(AL10.AL_ORIENTATION, listener.getOrientation());
	  
	  Log.info(this, "Listener values set!");
	}
	
	
//	public synchronized void addSource(SimpleSoundSoundPlayer p){
//		sources.add(p);
//	}
//	
//	public synchronized void RemoveSource(SimpleSoundSoundPlayer s){
//		int i;
//		boolean found = false;
//		for (i = 0; i < sources.size(); i++) {
//			if(sources.get(i).getId().equals(s.getId())){
//				found = true;
//				break;
//			}
//		}
//		if(found){
//			AL10.alDeleteSources(sources.get(i).getSourceBuffer());
//			sources.remove(i);
//		}
//	}
	
	

	@Override
	public void cleanUp() {
		//OpenALUtil.cleanUp(soundMap, sources);
		OpenALUtil.cleanUp(soundMap, sourcePool);
	}

	

	@Override
	public void initializeSoundEngine() {
		// TODO Auto-generated method stub
		
	}

	/**
	 * loads a Wave into a buffer
	 * @param soundPlayer 
	 */
	@Override
	public synchronized void loadSoundById(String id) {
		OpenALWave sound;
		//check if sound is already loaded
		if(!soundMap.containsKey(id)){
			sound = new OpenALWave(PATH, id+".wav");
			soundMap.put(id, sound);
			Log.info(this, id +" is loaded to a buffer.");
			Log.info(this, "Length of soundMap: "+ soundMap.size());
		} else{
			Log.info(this, id +" was already buffered.");
		}
	}

	@Override
	public void unloadSoundById(String id) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void stopAllPlayingSounds() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void loadSounds(String[] ids) {
		for (int i = 0; i < ids.length; i++) {
			loadSoundById(ids[i]);
		}
		
	}

	@Override
	public void registerListener(SoundListener l) {
		this.listener = l;
		setListenerValues();
	}

	@Override
	public float[] getListenerPosition() {
		FloatBuffer lp = listener.getPosition();
		float[] lpos = new float[]{lp.get(0), lp.get(1), lp.get(2)};
		return lpos;
	}

	@Override
	public float[] getListenerOrientation() {
		FloatBuffer lo = listener.getOrientation();
		float[] lori = new float[]{lo.get(0), lo.get(1), lo.get(2)};
		return lori;
	}


	public OpenALSource getOpenALSource() {
		return sourcePool;
	}


	public OpenALWave getOpenALWave(String id) {
		return soundMap.get(id);
	}


	public AcousticScanner getAcousticScanner() {
		if(acousticScanner == null){
			acousticScanner = new AcousticScanner();
		}
		return acousticScanner;
	}


	public GeometryManager getGeometryManager() {
		return geometryManager;
	}


	public void setGeometryManager(GeometryManager geometryManager) {
		this.geometryManager = geometryManager;
	}
	
	

}
